import os
import json
from app.utils.logger import logger

# 修复建议模板库
REPAIR_TEMPLATES = {
    'sql_injection': {
        'title': 'SQL注入漏洞修复建议',
        'description': 'SQL注入是一种常见的Web安全漏洞，攻击者可以通过构造特殊的输入来执行未授权的SQL命令。',
        'steps': [
            '使用参数化查询或预编译语句，避免直接拼接SQL语句。',
            '对所有用户输入进行严格的验证和过滤。',
            '实施最小权限原则，限制数据库用户的权限。',
            '使用ORM框架进行数据库操作。',
            '定期审计数据库查询日志，检测异常行为。'
        ],
        'code_examples': {
            'python': '''# 不安全的做法
query = "SELECT * FROM users WHERE username = '%s' AND password = '%s'" % (username, password)

# 安全的做法（使用参数化查询）
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))''',
            'java': '''// 不安全的做法
String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

// 安全的做法（使用预编译语句）
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();'''
        }
    },
    'xss': {
        'title': '跨站脚本（XSS）漏洞修复建议',
        'description': 'XSS漏洞允许攻击者在用户浏览器中执行恶意脚本，可能导致会话劫持、数据盗窃等严重问题。',
        'steps': [
            '对所有用户输入进行HTML转义处理。',
            '使用内容安全策略（CSP）来限制可以执行的脚本来源。',
            '实施输入验证，只允许指定的字符和格式。',
            '设置HttpOnly标志，防止JavaScript访问cookie。',
            '对富文本内容使用白名单过滤，而不是黑名单。'
        ],
        'code_examples': {
            'python': '''# 使用Flask的escape函数进行HTML转义
from flask import escape

safe_output = escape(user_input)

# 或者使用Jinja2模板的自动转义功能
# {{ user_input }} 会自动进行HTML转义''',
            'javascript': '''// 客户端转义示例
function escapeHtml(text) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}

const safeOutput = escapeHtml(userInput);'''
        }
    },
    'info_leak': {
        'title': '信息泄露漏洞修复建议',
        'description': '信息泄露可能导致敏感数据（如配置信息、源代码、用户数据等）被未授权访问。',
        'steps': [
            '移除或限制对敏感文件的访问权限。',
            '配置适当的文件系统权限和Web服务器设置。',
            '不要在客户端代码中硬编码敏感信息。',
            '使用环境变量或配置文件存储敏感信息，并限制其访问权限。',
            '实施访问控制，确保只有授权用户可以访问敏感信息。'
        ],
        'code_examples': {
            'apache': '''# Apache .htaccess 文件示例
# 禁止访问特定文件和目录
<FilesMatch "\.(env|git|svn|md|log)$">
    Order allow,deny
    Deny from all
</FilesMatch>

# 禁止目录列表
Options -Indexes''',
            'nginx': '''# Nginx 配置示例
# 禁止访问特定文件
location ~* \.(env|git|svn|md|log)$ {
    deny all;
}

# 禁止目录列表
autoindex off;'''
        }
    },
    'command_injection': {
        'title': '命令注入漏洞修复建议',
        'description': '命令注入允许攻击者在服务器上执行任意命令，可能导致完全的系统妥协。',
        'steps': [
            '避免使用用户输入直接构造系统命令。',
            '如果必须执行系统命令，使用参数化命令执行函数，并限制可执行的命令范围。',
            '实施输入验证，只允许特定的字符和命令。',
            '使用最小权限原则，以低权限用户身份执行系统命令。',
            '记录所有系统命令执行日志，以便监控异常行为。'
        ],
        'code_examples': {
            'python': '''# 不安全的做法
import os
os.system(f"ping -c 4 {user_input}")

# 安全的做法（使用subprocess并传递参数）
import subprocess
try:
    # 只允许ping命令，用户输入仅作为参数
    subprocess.run(['ping', '-c', '4', user_input], check=True)
except subprocess.CalledProcessError as e:
    print(f"Command failed: {e}")''',
            'php': '''// 不安全的做法
system("ping -c 4 " . $_GET['ip']);

// 安全的做法（使用escapeshellarg进行参数转义）
$ip = escapeshellarg($_GET['ip']);
system("ping -c 4 " . $ip);'''
        }
    },
    'csrf': {
        'title': '跨站请求伪造（CSRF）漏洞修复建议',
        'description': 'CSRF攻击诱导用户在已认证的Web应用程序上执行非预期的操作，可能导致未授权的数据修改或资金转账等。',
        'steps': [
            '为每个用户会话生成唯一的CSRF令牌。',
            '在所有状态改变的表单和AJAX请求中包含CSRF令牌。',
            '验证所有非GET请求中的CSRF令牌。',
            '设置适当的SameSite cookie属性。',
            '实施双重提交防护，在请求头和请求体中都包含CSRF令牌。'
        ],
        'code_examples': {
            'python': '''# Flask中的CSRF保护示例
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
csrf = CSRFProtect(app)

# 在模板中
# <form method="POST">
#     {{ csrf_token() }}
#     <!-- 其他表单字段 -->
# </form>''',
            'javascript': '''// 客户端AJAX请求中包含CSRF令牌
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

fetch('/api/action', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify(data)
});'''
        }
    },
    'default': {
        'title': '通用漏洞修复建议',
        'description': '以下是适用于大多数类型漏洞的通用修复措施。',
        'steps': [
            '实施输入验证和输出编码。',
            '遵循最小权限原则，限制系统和应用程序的访问权限。',
            '保持软件和依赖项更新到最新版本。',
            '实施适当的访问控制机制。',
            '定期进行安全审计和漏洞扫描。',
            '培训开发人员了解安全最佳实践。'
        ],
        'code_examples': {}
    },
    'path_traversal': {
        'title': '路径遍历漏洞修复建议',
        'description': '路径遍历漏洞允许攻击者访问文件系统中未授权的文件和目录，可能导致敏感信息泄露或系统妥协。',
        'steps': [
            '对所有用户输入的路径进行严格验证，只允许访问预期的目录和文件。',
            '使用白名单方式验证文件路径，而不是黑名单。',
            '实施路径规范化，消除特殊字符（如../）。',
            '使用绝对路径，并验证请求的路径是否在允许的基目录内。',
            '使用文件系统API的安全函数，避免直接拼接路径。',
            '限制应用程序的文件系统访问权限。'
        ],
        'code_examples': {
            'python': '''# 不安全的做法
file_path = base_dir + user_input  # 可能导致路径遍历

# 安全的做法
import os
from pathlib import Path
def safe_path_join(base_dir, user_path):
    # 确保路径在允许的基目录内
    base_dir = Path(base_dir).resolve()
    target_path = (base_dir / user_path).resolve()
    # 验证路径是否在基目录下
    if base_dir not in target_path.parents and base_dir != target_path:
        raise Exception("访问被拒绝")
    return str(target_path)

try:
    safe_file_path = safe_path_join("/app/data", user_input)
    with open(safe_file_path, 'r') as f:
        content = f.read()
except Exception as e:
    # 处理访问被拒绝的情况''',
            'php': '''// 不安全的做法
$file = "../files/" . $_GET['file']; // 危险！

// 安全的做法
function secureFileAccess($basePath, $userPath) {
    $realBase = realpath($basePath);
    $realUserPath = realpath($basePath . '/' . $userPath);
    
    // 检查请求的文件是否在允许的目录内
    if ($realUserPath !== false && strpos($realUserPath, $realBase) === 0) {
        return $realUserPath;
    }
    
    throw new Exception("访问被拒绝");
}

try {
    $file = secureFileAccess("/var/www/files", $_GET['file']);
    readfile($file);
} catch (Exception $e) {
    // 处理错误'''
        }
    },
    'file_upload': {
        'title': '不安全的文件上传漏洞修复建议',
        'description': '不安全的文件上传漏洞允许攻击者上传恶意文件（如WebShell）到服务器，可能导致完全的系统控制。',
        'steps': [
            '实施严格的文件类型验证，检查MIME类型、文件扩展名和文件内容。',
            '将上传的文件存储在Web根目录之外，或使用单独的域名/CDN提供文件服务。',
            '为上传的文件生成随机文件名，避免使用用户提供的文件名。',
            '实施文件内容验证，使用文件签名或魔术字节检测真实文件类型。',
            '限制上传文件的大小和数量。',
            '配置适当的文件权限，防止执行上传的文件。',
            '使用防病毒/恶意软件扫描工具检查上传的文件。'
        ],
        'code_examples': {
            'python': '''# Flask文件上传安全示例
from flask import Flask, request, redirect, url_for
import os
from werkzeug.utils import secure_filename
import magic

app = Flask(__name__)
UPLOAD_FOLDER = '/var/www/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'doc', 'docx', 'jpg', 'png', 'gif'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        return redirect(request.url)
    if file and allowed_file(file.filename):
        # 验证MIME类型
        mime = magic.Magic(mime=True)
        file_content = file.stream.read()
        file.stream.seek(0)  # 重置文件指针
        mime_type = mime.from_buffer(file_content)
        
        # 检查是否为允许的MIME类型
        allowed_mime_types = ['text/plain', 'application/pdf', 'image/jpeg', 'image/png']
        if mime_type not in allowed_mime_types:
            return "不支持的文件类型", 400
        
        # 生成安全的文件名
        import uuid
        _, ext = os.path.splitext(secure_filename(file.filename))
        safe_filename = str(uuid.uuid4()) + ext
        
        # 保存文件到安全位置
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], safe_filename))
        return '文件上传成功''',
            'php': '''// PHP文件上传安全示例
function secureFileUpload($file) {
    // 允许的文件类型
    $allowed_types = [
        'image/jpeg' => ['jpg', 'jpeg'],
        'image/png' => ['png'],
        'application/pdf' => ['pdf']
    ];
    
    // 检查文件是否有错误
    if ($file['error'] !== UPLOAD_ERR_OK) {
        return false;
    }
    
    // 检查文件大小（限制为5MB）
    if ($file['size'] > 5 * 1024 * 1024) {
        return false;
    }
    
    // 验证MIME类型
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime_type = $finfo->file($file['tmp_name']);
    
    if (!array_key_exists($mime_type, $allowed_types)) {
        return false;
    }
    
    // 创建安全的文件名
    $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
    $safe_filename = uniqid('', true) . '.' . $extension;
    
    // 确保扩展名与MIME类型匹配
    if (!in_array(strtolower($extension), $allowed_types[$mime_type])) {
        return false;
    }
    
    // 保存到安全位置（Web根目录外）
    $upload_path = '/var/uploads/' . $safe_filename;
    if (move_uploaded_file($file['tmp_name'], $upload_path)) {
        // 设置适当的文件权限
        chmod($upload_path, 0644); // 只读
        return $safe_filename;
    }
    
    return false;
}

// 使用示例
if (isset($_FILES['upload_file'])) {
    $result = secureFileUpload($_FILES['upload_file']);
    if ($result) {
        echo "文件上传成功: $result";
    } else {
        echo "文件上传失败";
    }
}'''
        }
    },
    'weak_password': {
        'title': '弱密码漏洞修复建议',
        'description': '弱密码是最常见的安全漏洞之一，容易被暴力破解或字典攻击，可能导致账户被未授权访问。',
        'steps': [
            '实施强密码策略，要求密码长度至少为12个字符。',
            '强制密码包含大小写字母、数字和特殊字符的组合。',
            '使用密码强度检查库验证用户输入的密码强度。',
            '禁止使用常见密码或包含用户名的密码。',
            '实施账户锁定机制，在多次登录失败后暂时锁定账户。',
            '实施双因素认证（2FA）作为额外的安全层。',
            '存储密码时使用强哈希算法（如bcrypt、Argon2）并添加适当的盐值。',
            '定期要求用户更改密码。'
        ],
        'code_examples': {
            'python': '''# 使用Flask-Security进行密码管理
from flask import Flask
from flask_security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret-key'

# 密码强度检查示例
import re
def check_password_strength(password):
    # 至少12个字符
    if len(password) < 12:
        return False, "密码长度必须至少为12个字符"
    # 包含至少一个大写字母
    if not re.search(r'[A-Z]', password):
        return False, "密码必须包含至少一个大写字母"
    # 包含至少一个小写字母
    if not re.search(r'[a-z]', password):
        return False, "密码必须包含至少一个小写字母"
    # 包含至少一个数字
    if not re.search(r'[0-9]', password):
        return False, "密码必须包含至少一个数字"
    # 包含至少一个特殊字符
    if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
        return False, "密码必须包含至少一个特殊字符"
    return True, "密码强度良好"

# 存储密码示例
def store_password(username, password, user_id):
    # 检查密码强度
    is_strong, message = check_password_strength(password)
    if not is_strong:
        return False, message
    
    # 生成密码哈希
    password_hash = generate_password_hash(password, method='pbkdf2:sha256:260000', salt_length=16)
    
    # 这里应该存储到数据库
    # db.session.add(User(user_id=user_id, username=username, password=password_hash))
    # db.session.commit()
    
    return True, "密码设置成功"''',
            'nodejs': '''// 使用bcrypt进行密码哈希和验证
const bcrypt = require('bcrypt');
const saltRounds = 12;

// 密码强度检查
function checkPasswordStrength(password) {
    // 至少12个字符
    if (password.length < 12) return { isValid: false, message: "密码长度必须至少为12个字符" };
    // 包含至少一个大写字母
    if (!/[A-Z]/.test(password)) return { isValid: false, message: "密码必须包含至少一个大写字母" };
    // 包含至少一个小写字母
    if (!/[a-z]/.test(password)) return { isValid: false, message: "密码必须包含至少一个小写字母" };
    // 包含至少一个数字
    if (!/\d/.test(password)) return { isValid: false, message: "密码必须包含至少一个数字" };
    // 包含至少一个特殊字符
    if (!/[^A-Za-z0-9]/.test(password)) return { isValid: false, message: "密码必须包含至少一个特殊字符" };
    return { isValid: true, message: "密码强度良好" };
}

// 存储密码
async function storePassword(username, password, userId) {
    // 检查密码强度
    const strengthResult = checkPasswordStrength(password);
    if (!strengthResult.isValid) {
        return strengthResult;
    }
    
    try {
        // 生成密码哈希
        const hashedPassword = await bcrypt.hash(password, saltRounds);
        
        // 这里应该存储到数据库
        // await db.collection('users').updateOne({ userId }, { $set: { username, password: hashedPassword } });
        
        return { isValid: true, message: "密码设置成功" };
    } catch (error) {
        return { isValid: false, message: "密码处理失败" };
    }
}

// 验证密码
async function verifyPassword(storedHash, providedPassword) {
    return await bcrypt.compare(providedPassword, storedHash);
}'''
        }
    },
    'subdomain_takeover': {
        'title': '子域名接管漏洞修复建议',
        'description': '子域名接管漏洞发生在子域名解析到不再使用的外部服务（如AWS S3、GitHub Pages等）时，攻击者可以注册该服务并接管子域名。',
        'steps': [
            '定期审计所有子域名，识别不再使用的子域名。',
            '删除或修复指向不存在资源的DNS记录。',
            '对于使用外部服务的子域名，确保账户安全并启用所有可用的安全控制。',
            '为DNS记录设置TTL值，以便在需要时快速更新。',
            '实施DNSSEC，增加DNS记录的安全性。',
            '使用监控工具检测子域名状态变化。',
            '为所有子域名实施HTTPS和适当的安全头。'
        ],
        'code_examples': {
            'dns_config': '''# DNS记录审计示例（使用dig命令）
dig +short subdomain.example.com  # 检查是否返回IP地址

# 检查CNAME记录
dig +short CNAME subdomain.example.com

# 常见的危险记录类型
# 1. 指向AWS S3的CNAME记录
# 2. 指向Heroku的CNAME记录
# 3. 指向GitHub Pages的CNAME记录
# 4. 指向其他云服务提供商的记录''',
            'aws_s3_protection': '''# AWS S3 存储桶保护

# 1. 确保存储桶名称与域名匹配时，所有者就是域名的所有者
# 2. 启用存储桶策略禁止公共访问
{
  "Version": "2012-10-17",
  "Id": "ExamplePolicy",
  "Statement": [
    {
      "Sid": "DenyPublicAccess",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::subdomain.example.com/*",
      "Condition": {
        "StringNotEquals": {
          "aws:SourceArn": "arn:aws:cloudfront::123456789012:distribution/ABCDEF1234567"
        }
      }
    }
  ]
}

# 3. 启用AWS S3访问日志记录'''
        }
    },
    'cors_misconfiguration': {
        'title': 'CORS配置错误修复建议',
        'description': '跨域资源共享（CORS）配置错误可能允许恶意网站访问敏感数据，导致跨站数据泄露。',
        'steps': [
            '不要使用通配符（*）作为Access-Control-Allow-Origin头的值，除非绝对必要。',
            '当设置Access-Control-Allow-Credentials为true时，Access-Control-Allow-Origin不能是通配符。',
            '实施严格的来源验证，只允许受信任的域名。',
            '限制Access-Control-Allow-Methods为应用程序实际需要的HTTP方法。',
            '谨慎使用Access-Control-Allow-Headers，避免暴露敏感头信息。',
            '对于API服务，考虑使用API密钥或OAuth等更强大的认证机制。',
            '对预检请求（OPTIONS）实施适当的处理和缓存策略。'
        ],
        'code_examples': {
            'nodejs_express': '''// Express.js 安全的CORS配置
const express = require('express');
const cors = require('cors');
const app = express();

// 允许特定来源
const allowedOrigins = ['https://trusted-website.com', 'https://admin.yourapp.com'];

const corsOptions = {
  origin: function (origin, callback) {
    // 检查origin是否在允许列表中
    if (allowedOrigins.includes(origin) || !origin) { // 允许服务器到服务器的请求
      callback(null, true);
    } else {
      callback(new Error('不允许的跨域请求'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE'], // 限制允许的HTTP方法
  allowedHeaders: ['Content-Type', 'Authorization'], // 限制允许的头
  credentials: true, // 允许包含凭证（仅在验证来源后启用）
  maxAge: 86400 // 预检请求缓存时间（秒）
};

// 应用CORS中间件
app.use(cors(corsOptions));

// 对于更精细的控制，可以为不同的路由设置不同的CORS策略
app.get('/public-data', cors({ origin: '*' }), (req, res) => {
  // 公开数据的处理
});

app.get('/private-data', cors(corsOptions), (req, res) => {
  // 私有数据的处理
});''',
            'python_flask': '''# Flask 安全的CORS配置
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# 允许特定来源
allowed_origins = ['https://trusted-website.com', 'https://admin.yourapp.com']

# 配置CORS
cors = CORS(app, resources={
    r"/api/*": {
        "origins": allowed_origins,
        "methods": ["GET", "POST", "PUT", "DELETE"],
        "allow_headers": ["Content-Type", "Authorization"],
        "supports_credentials": True,
        "max_age": 86400
    },
    # 为公开资源设置不同的策略
    r"/public/*": {
        "origins": "*",
        "methods": ["GET"],
        "max_age": 86400
    }
})

# 或者为特定路由配置不同的CORS策略
@app.route('/public-data')
def public_data():
    # 公开数据的处理
    pass

@app.route('/private-data')
def private_data():
    # 私有数据的处理，会应用上面配置的严格CORS策略
    pass'''
        }
    },
    'ssl_tls_issues': {
        'title': 'SSL/TLS配置问题修复建议',
        'description': 'SSL/TLS配置不当可能导致中间人攻击、数据泄露或服务不可用，正确的配置对于保护通信安全至关重要。',
        'steps': [
            '为所有服务启用HTTPS，并确保证书有效且定期更新。',
            '配置HTTP到HTTPS的强制重定向。',
            '实施HTTP严格传输安全（HSTS）头，防止协议降级攻击。',
            '禁用不安全的SSL/TLS版本（如SSL 2.0、SSL 3.0、TLS 1.0和TLS 1.1）。',
            '仅启用强密码套件，禁用弱加密算法。',
            '配置证书透明度（CT）监控。',
            '使用可信的证书颁发机构（CA）签发证书。',
            '定期使用SSL/TLS扫描工具（如SSL Labs）检查配置。'
        ],
        'code_examples': {
            'nginx_config': '''# Nginx 安全的SSL/TLS配置
server {
    listen 80;
    server_name example.com;
    # HTTP到HTTPS重定向
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    
    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    
    # 安全配置
    ssl_protocols TLSv1.2 TLSv1.3; # 仅启用现代TLS版本
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    
    # HSTS配置
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    
    # 其他安全头
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-XSS-Protection "1; mode=block";
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # 网站内容配置
    root /var/www/html;
    index index.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
}''',
            'apache_config': '''# Apache 安全的SSL/TLS配置
<VirtualHost *:80>
    ServerName example.com
    # HTTP到HTTPS重定向
    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    
    # SSL证书配置
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key
    SSLCertificateChainFile /etc/ssl/certs/ca-bundle.crt
    
    # 安全配置
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    SSLHonorCipherOrder on
    SSLCipherSuite "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
    
    # HSTS配置
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    
    # 其他安全头
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"
    
    # 网站内容配置
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>'''
        }
    },
    'ssrf': {
        'title': '服务器端请求伪造(SSRF)漏洞修复建议',
        'description': 'SSRF漏洞允许攻击者诱导服务器向意外的目标发起请求，可能导致内部网络探测、云服务元数据获取、本地文件读取等严重安全问题。',
        'steps': [
            '实施URL白名单机制，只允许连接到预定义的、受信任的域名和IP地址。',
            '禁止访问内部网络地址，包括127.0.0.1、localhost、私有IP地址范围(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)。',
            '禁止访问云服务元数据端点，如AWS(169.254.169.254)、GCP(metadata.google.internal)、Azure(169.254.169.254)。',
            '使用DNS解析库验证主机名，拒绝解析到内部IP的域名。',
            '限制请求的协议，只允许HTTP、HTTPS等必要协议。',
            '设置适当的超时时间，防止慢速攻击。',
            '实施请求资源限制，如大小限制、频率限制等。'
        ],
        'code_examples': {
            'python': '''# 安全的URL处理示例
import ipaddress
import socket
from urllib.parse import urlparse

def is_safe_url(url):
    # 解析URL
    parsed = urlparse(url)
    
    # 检查协议
    if parsed.scheme not in ['http', 'https']:
        return False, "不允许的协议"
    
    # 获取主机名
    hostname = parsed.hostname
    if not hostname:
        return False, "无效的主机名"
    
    # 解析IP地址
    try:
        ip_address = socket.gethostbyname(hostname)
    except socket.gaierror:
        return False, "无法解析主机名"
    
    # 检查是否为内部IP
    try:
        ip_obj = ipaddress.ip_address(ip_address)
        # 检查是否为环回地址
        if ip_obj.is_loopback:
            return False, "禁止访问环回地址"
        # 检查是否为私有地址
        if ip_obj.is_private:
            return False, "禁止访问私有地址"
        # 检查是否为链路本地地址
        if ip_obj.is_link_local:
            return False, "禁止访问链路本地地址"
        # 检查云服务元数据地址
        if ip_address == '169.254.169.254':
            return False, "禁止访问云服务元数据"
    except ValueError:
        return False, "无效的IP地址"
    
    # 检查白名单（可选）
    allowed_domains = ['trusted-domain.com', 'api.allowed-service.com']
    if hostname not in allowed_domains and not any(hostname.endswith(f".{domain}") for domain in allowed_domains):
        return False, "主机名不在白名单中"
    
    return True, "URL验证通过"

# 使用示例
def fetch_external_resource(user_provided_url):
    is_safe, message = is_safe_url(user_provided_url)
    if not is_safe:
        raise SecurityError(f"不安全的URL: {message}")
    
    # 安全的请求处理
    # response = requests.get(user_provided_url, timeout=10)''',
            'java': '''// Java中安全的URL处理示例
import java.net.*;
import java.util.Arrays;
import java.util.List;

public class SafeUrlValidator {
    // 允许的协议
    private static final List<String> ALLOWED_PROTOCOLS = Arrays.asList("http", "https");
    
    // 白名单域名
    private static final List<String> ALLOWED_DOMAINS = Arrays.asList(
        "trusted-domain.com", "api.allowed-service.com"
    );
    
    public static boolean isValidUrl(String url) throws MalformedURLException {
        URL parsedUrl = new URL(url);
        
        // 验证协议
        if (!ALLOWED_PROTOCOLS.contains(parsedUrl.getProtocol())) {
            return false;
        }
        
        String hostname = parsedUrl.getHost();
        
        // 检查是否为白名单域名
        boolean isAllowedDomain = false;
        for (String allowedDomain : ALLOWED_DOMAINS) {
            if (hostname.equals(allowedDomain) || hostname.endsWith("." + allowedDomain)) {
                isAllowedDomain = true;
                break;
            }
        }
        
        if (!isAllowedDomain) {
            return false;
        }
        
        try {
            // 解析IP并检查是否为内部地址
            InetAddress[] addresses = InetAddress.getAllByName(hostname);
            for (InetAddress addr : addresses) {
                if (addr.isLoopbackAddress() || addr.isSiteLocalAddress() || 
                    addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
                    return false;
                }
                // 检查云服务元数据地址
                if (addr.getHostAddress().equals("169.254.169.254")) {
                    return false;
                }
            }
        } catch (UnknownHostException e) {
            return false;
        }
        
        return true;
    }
}'''
        }
    }
}

# LLM集成配置
LLM_CONFIG = {
    'enabled': False,  # 默认禁用LLM集成
    'api_key': os.environ.get('OPENAI_API_KEY', ''),
    'model': 'gpt-3.5-turbo',
    'temperature': 0.7
}

def generate_suggestion(vulnerability):
    """为漏洞生成修复建议"""
    try:
        # 获取漏洞类型
        vuln_type = vulnerability.get('vuln_type', 'unknown')
        
        # 首先尝试使用模板化建议
        template = REPAIR_TEMPLATES.get(vuln_type, REPAIR_TEMPLATES['default'])
        
        # 构建建议文本
        suggestion = f"# {template['title']}\n\n"
        suggestion += f"{template['description']}\n\n"
        suggestion += "## 修复步骤\n"
        for i, step in enumerate(template['steps'], 1):
            suggestion += f"{i}. {step}\n"
        
        # 如果有代码示例，添加到建议中
        if template['code_examples']:
            suggestion += "\n## 代码示例\n"
            for lang, code in template['code_examples'].items():
                suggestion += f"\n### {lang.title()}\n```\n{code}\n```\n"
        
        # 添加风险说明
        risk_score = vulnerability.get('risk_score', 0.5)
        severity = vulnerability.get('severity', 'medium')
        suggestion += f"\n## 风险评估\n"\
                     f"风险评分: {risk_score:.2f} ({severity})\n"\
                     f"建议立即修复此漏洞以避免潜在的安全风险。\n"
        
        # 可选：尝试使用LLM生成更具体的建议
        # 如果启用了LLM集成且有API密钥，可以调用OpenAI等服务
        if LLM_CONFIG['enabled'] and LLM_CONFIG['api_key']:
            try:
                llm_suggestion = generate_llm_suggestion(vulnerability)
                if llm_suggestion:
                    suggestion += "\n## AI生成的具体建议（仅供参考，需人工确认）\n"
                    suggestion += llm_suggestion
            except Exception as e:
                logger.warning(f"Failed to generate LLM suggestion: {str(e)}")
        
        return suggestion
        
    except Exception as e:
        logger.error(f"Error generating repair suggestion: {str(e)}")
        # 返回默认建议
        return "无法生成修复建议。建议咨询安全专家进行漏洞评估和修复。"

def generate_llm_suggestion(vulnerability):
    """使用LLM生成修复建议（预留接口）"""
    try:
        # 注意：在实际实现中，这里应该调用OpenAI API或其他LLM服务
        # 但为了演示和避免API调用，我们返回一个模拟的响应
        
        # 构建提示信息
        prompt = build_llm_prompt(vulnerability)
        
        # 这里是模拟的LLM响应
        # 在实际应用中，应该替换为真实的API调用
        mock_response = "这是AI生成的修复建议示例。在实际部署中，这里将包含基于漏洞具体情况的个性化建议。\n\n"\
                        "请注意，AI生成的建议仅供参考，在应用到生产环境前必须经过安全专家的人工审核和测试。"
        
        return mock_response
        
    except Exception as e:
        logger.error(f"Error in LLM suggestion generation: {str(e)}")
        return None

def build_llm_prompt(vulnerability):
    """构建LLM提示信息"""
    vuln_type = vulnerability.get('vuln_type', 'unknown')
    path = vulnerability.get('path', '')
    payload = vulnerability.get('payload', '')
    evidence = vulnerability.get('evidence', '')
    
    prompt = f"作为一名网络安全专家，请分析以下漏洞并提供详细的修复建议：\n\n"\
             f"漏洞类型: {vuln_type}\n"\
             f"影响路径: {path}\n"\
             f"攻击载荷: {payload}\n"\
             f"发现证据: {evidence}\n\n"\
             f"请提供具体的修复步骤、代码示例（如果适用）和预防措施。\n"\
             f"请确保建议是可行的、安全的，并遵循行业最佳实践。\n"\
             f"输出格式请使用Markdown。"
    
    return prompt

def get_suggestion_template(vuln_type):
    """获取特定类型漏洞的建议模板"""
    return REPAIR_TEMPLATES.get(vuln_type, REPAIR_TEMPLATES['default'])

def update_suggestion_template(vuln_type, template):
    """更新漏洞建议模板"""
    try:
        # 验证模板结构
        required_keys = ['title', 'description', 'steps']
        for key in required_keys:
            if key not in template:
                raise ValueError(f"Missing required template key: {key}")
        
        # 更新模板
        REPAIR_TEMPLATES[vuln_type] = template
        
        # 可选：持久化模板更新
        # save_templates_to_file()
        
        logger.info(f"Updated suggestion template for {vuln_type}")
        return True
        
    except Exception as e:
        logger.error(f"Error updating suggestion template: {str(e)}")
        return False

def toggle_llm_integration(enabled, api_key=None):
    """启用或禁用LLM集成"""
    global LLM_CONFIG
    
    try:
        LLM_CONFIG['enabled'] = enabled
        if api_key:
            LLM_CONFIG['api_key'] = api_key
        
        logger.info(f"LLM integration {'enabled' if enabled else 'disabled'}")
        return True
        
    except Exception as e:
        logger.error(f"Error toggling LLM integration: {str(e)}")
        return False